#ifndef _DVMGPU_RTS_H_
#define _DVMGPU_RTS_H_

#include <stdlib.h>

#include "system_typ.h"
#include "util.h"

// Структура, описывающая массив
typedef struct {
    s_DISARRAY *dvmDisArray; // ссылка на s_DISARRAY DVM-массива
    long *header; // основной заголовок
    long **additionalHeaders; // дополнительные заголовки для этой порции массива
    int additionalHeadersCount;
    void *deviceAddr; // адрес, где фактически на девайсе лежат данные. =0, если не аллоцирован
    int rank; // размерность
    int typeSize; // размер в байтах одного элемента
    Interval *havePortion; // описание имеющейся на девайсе порции массива. Нижний,Верхний(включительно) индексы по каждому измерению.
    Interval *needPortion;  // описание необходимой для выполнения цикла порции массива. Нижний,Верхний(включительно) индексы по каждому измерению.
    int copyinFlag;
    int copyoutFlag; 
} DvmGpuArrayHeaderStruct;

enum RegionType {RT_DATA, RT_COMPUTE};

// Структура, описывающая регионы
typedef struct tag_DvmGpuRegion {
    enum RegionType regionType; // RT_DATA, RT_COMPUTE
    struct tag_DvmGpuRegion *parentRegion; // Объемлющий регион
    DvmGpuArrayHeaderStruct **arrays; // Массивы, доступные в регионе. Это свои массивы + все по иерархии регионов вверх
    int arraysCount;
    DvmGpuArrayHeaderStruct **myArrays; // Массивы, впервые описанные в этом регионе (то есть описанные в нём и не описанные на уровне выше)
    int myArraysCount;
    long **additionalHeaders; // Список дополнительных заголовков массивов, появившихся в этом регионе. Нужен, чтобы отсоединить их по окончанию региона
    int additionalHeadersCount;
} DvmGpuRegion, *DvmGpuRegionRef;

// Структура, описывающая регион данных:
typedef DvmGpuRegion DvmGpuDataRegion, *DvmGpuDataRegionRef;

// Структура, описывающая вычислительный регион:
typedef DvmGpuRegion DvmGpuComputeRegion, *DvmGpuComputeRegionRef;

// Структура, описывающая редукционную переменную(массив)
typedef struct {
    s_REDVAR *dvmRVar; // ссылка на s_REDVAR редукционной переменной DVM
    char *array; // ссылка на фактическое расположение редукционной переменной
    int arrayLength; // количество элементов в редукционном массиве
    int arrayElementType; // тип элемента редукционного массива
    int arrayElementSize; // размер в байтах одного элемента редукционного массива
    char *arrayBackup; // временное хранилище начального значения переменной (чтобы не просуммировалась огромное количество раз)
    char *locArray; // ссылка на фактическое расположение LOC-массива
    int locElementSize; // размер в байтах одного элемента LOC-массива
    unsigned char funcNumber; // номер редукционной функции

    char *gpuMem; // ссылка на аллоцированную на девайсе память
    char *gpuLocMem;
    void *arrayBaseAddr; // база для массива промежуточных значений редукционной переменной
    void *locBaseAddr; // база для массива промежуточных значений LOC-массива
    IndexType *gpuOffsetPtr; // ссылка на переменную, в которую следует вписывать смещение массива промежуточных значений редукционной переменной
    IndexType *gpuLocOffsetPtr; // ссылка на переменную, в которую следует вписывать смещение массива промежуточных значений LOC-массива
} Reduction, *ReductionRef;

// Структура, описывающая DVM_GPU цикл:
typedef struct {
    DvmGpuComputeRegion *region; // Вычислительный регион, в котором цикл
    s_PARLOOP *dvmLoop; // Ссылка на s_PARLOOP DVM-цикла
    int dimension; // Количество измерений
    LoopBounds *loopBounds; // подпараллелепипед витков DVM-цикла, который поступил извне и хочет быть выполнен на GPU
    int firstLoopInRegion; // признак того, что цикл – первый в данном вычислительном регионе. Полезно при квантовании, но необязательно – можно и объявлять все циклы непервыми
    int lastLoopInRegion; // признак того, что цикл – последний в данном вычислительном регионе. Полезно при квантовании, но необязательно – можно и объявлять все циклы непоследними
    Reduction **reductions;
    int reductionsCount;

    int counter; // Временное решение для управления ходом исполнения цикла - 0 - только начался, 1 - в обработке, 2 - кончился
    int restBlocks; // Количество пока не обработанных блоков
    int latestBlocks; // Количество посланных в последний раз на обработку блоков
    int overallBlocks; // Общее количество блоков(на весь входной цикл)
} DvmGpuLoop, *DvmGpuLoopRef;

// Структура, описывающая вырезку-подмассив по одному измерению
typedef struct {
    DvmGpuArrayHeaderStruct *array; // ссылка на описатель массива
    int dim; // номер измерения(нумерация с единицы)
    long beginIndex; // начальный индекс
    long endIndex; // конечный индекс
} SliceDesc;

// Структура, описывающая теневую грань
typedef struct {
    SliceDesc *sliceDescs; // вырезки-подмассивы
    int slicesCount;
} DvmGpuShadow, *DvmGpuShadowRef;

#endif
